﻿using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using ST.Common.Util;
using ST.Common.Util.Security;
using ST.Common.Util.Text;
using ST.Common.Util.Xml;
using ST.WX.Common.Exceptions;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Xml;

namespace ST.WX.Common.Pay
{
	/// <summary>
	/// 微信请求响应
	/// </summary>
	public class WXPayRet : WXPayBase
	{
		/// <summary>
		/// 返回状态码
		/// </summary>
		public string return_code { get; private set; }

		/// <summary>
		/// 返回信息
		/// </summary>
		public string return_msg { get; private set; }

		/// <summary>
		/// 业务结果（SUCCESS/FAIL）
		/// </summary>
		[StringLength(16)]
		public string result_code { get; private set; }

		/// <summary>
		/// 错误代码
		/// </summary>
		[StringLength(32)]
		public string err_code { get; private set; }

		/// <summary>
		/// 错误代码描述
		/// </summary>
		[StringLength(128)]
		public string err_code_des { get; private set; }

		/// <summary>
		/// 返回的所有值
		/// </summary>
		[JsonIgnore]
		protected SortedDictionary<string, object> values { get; set; }

		/// <summary>
		/// 成功时返回内容
		/// </summary>
		/// <returns></returns>
		public string ResponseSuccess()
		{
			return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
		}

		/// <summary>
		/// 失败时返回内容
		/// </summary>
		/// <param name="msg"></param>
		/// <returns></returns>
		public string ResponseFail(string msg)
		{
			return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[" + msg + "]]></return_msg></xml>";
		}

		public WXPayRet() : base()
		{
			values = new SortedDictionary<string, object>();
		}

		public WXPayRet(string appID, string mchID, string mchKey, WXPaySignType signType) : base(appID, mchID, mchKey, signType)
		{
			values = new SortedDictionary<string, object>();
		}

		/// <summary>
		/// 接收响应时解析xml格式
		/// </summary>
		/// <param name="xml"></param>
		/// <returns></returns>
		protected virtual void FromXml(string xml)
		{
			if (string.IsNullOrEmpty(xml))
			{
				throw new WXPayException("xml内容为空!");
			}
			try
			{
				SafeXmlDocument xmlDoc = new SafeXmlDocument();
				xmlDoc.LoadXml(xml);
				XmlNode xmlNode = xmlDoc.DocumentElement;//获取到根节点<xml>
				XmlNodeList nodes = xmlNode.ChildNodes;
				foreach (XmlNode xn in nodes)
				{
					XmlElement xe = (XmlElement)xn;
					values[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中
				}
			}
			catch (XmlException ex)
			{
				throw new WXPayException("解析xml内容出错，" + ex.Message, ex);
			}
			catch (WXPayException ex)
			{
				throw ex;
			}
		}

		/// <summary>
		/// 接收响应时校验参数
		/// </summary>
		public virtual void Validate()
		{
			if (return_code != "SUCCESS")
			{
				throw new WXPayException(return_msg);
			}
			if (string.IsNullOrEmpty(appid))
			{
				throw new WXPayException("appid不能为空");
			}
			if (string.IsNullOrEmpty(mch_id))
			{
				throw new WXPayException("商户号不能为空");
			}
			if (string.IsNullOrEmpty(mch_key))
			{
				throw new WXPayException("支付密钥不能为空");
			}
			if (string.IsNullOrEmpty(sign))
			{
				throw new WXPayException("响应结果不包含签名");
			}
			//转url格式
			string str = ToUrl(values);
			str += "&key=" + mch_key;
			string signCalc = string.Empty;
			switch (sign_type)
			{
				case WXPaySignType.MD5:
					signCalc = EncryptHelper.MD5Hash(str, true);
					break;
				case WXPaySignType.HMACSHA256:
					signCalc = EncryptHelper.SHA256Hash(str, mch_key, true);
					break;
				default:
					throw new WXPayException("响应结果签名算法不支持");
			}
			if (signCalc != sign)
			{
				throw new WXPayException("响应结果签名验证不一致");
			}
		}

		/// <summary>
		/// 接收响应时校验参数
		/// </summary>
		/// <param name="mchKey"></param>
		public virtual void Validate(string mchKey)
		{
			mch_key = mchKey;
			Validate();
		}

		protected virtual void ConvertToObj()
		{
			if (values.ContainsKey("appid"))
			{
				appid = Convert.ToString(values["appid"]);
			}
			if (values.ContainsKey("mch_id"))
			{
				mch_id = Convert.ToString(values["mch_id"]);
			}
			if (values.ContainsKey("sign"))
			{
				sign = Convert.ToString(values["sign"]);
			}
			if (values.ContainsKey("nonce_str"))
			{
				nonce_str = Convert.ToString(values["nonce_str"]);
			}
			if (values.ContainsKey("return_code"))
			{
				return_code = Convert.ToString(values["return_code"]);
			}
			if (values.ContainsKey("return_msg"))
			{
				return_msg = Convert.ToString(values["return_msg"]);
			}
			if (values.ContainsKey("result_code"))
			{
				result_code = Convert.ToString(values["result_code"]);
			}
			if (values.ContainsKey("err_code"))
			{
				err_code = Convert.ToString(values["err_code"]);
			}
			if (values.ContainsKey("err_code_des"))
			{
				err_code_des = Convert.ToString(values["err_code_des"]);
			}
			if (values.ContainsKey("sign_type"))
			{
				string signType = Convert.ToString(values["sign_type"]);
				switch (signType)
				{
					case SIGN_TYPE_HMACSHA256:
						sign_type = WXPaySignType.HMACSHA256;
						break;
					case SIGN_TYPE_MD5:
						sign_type = WXPaySignType.MD5;
						break;
				}
			}
			else
			{
				sign_type = WXPaySignType.MD5;//默认MD5
			}
		}

		/// <summary>
		/// 解析xml值并填充到对象中
		/// </summary>
		/// <param name="xml"></param>
		public virtual void ParseAndValidate(string xml)
		{
			FromXml(xml);
			ConvertToObj();
			Validate();
		}

		/// <summary>
		/// 解析xml值并填充到对象中（仅限微信主动推送使用）
		/// </summary>
		/// <param name="xml"></param>
		public virtual void Parse(string xml)
		{
			FromXml(xml);
			ConvertToObj();
		}
	}
}
